# -*- coding: utf-8 -*-
# created on 2016/10/26

from sympy import log, Pow, Symbol, simplify, Add
from sympy.core.mul import Mul
from mathsolver.functions.base.objects import BaseEq, BasePoints, BasePoint, BaseEqs
from mathsolver.functions.base.base import BaseFunction
from mathsolver.functions.fangcheng.fenshi import FenShi001
from mathsolver.functions.root.jiefangchenzu import JieFangChenZu
from mathsolver.functions.root.jiefangchen import JieFangChen


class HanShuDingDian(BaseFunction):
    def solver(self, *args):
        """
        求输入函数恒过定点

        :param args: [0] - BaseFunc
            指数型函数y=f(x)*a**(g(x))+h(x)
            对数型函数y=f(x)*log(g(x),a)+h(x)
            幂型函数y=f(x)*g(x)**a+h(x)
            非指对幂型函数

        :return: BasePoint - 恒过点
        """
        expr = args[0].expression
        points = self.__get_special_points(args[0].name, expr, args[0].var)
        if points is None:
            return self
        if len(points) == 1:
            self.output.append(BasePoint(
                {'name': '', 'value': [str(points.args[0]), str(simplify(expr.subs(args[0].var, points.args[0])))]}))
        elif len(points) > 1:
            pointlist = []
            for p in points:
                pointlist.append({'name': '', 'value': [str(p), str(simplify(expr.subs(args[0].var, p)))]})
            self.output.append(BasePoints(pointlist))
        self.label.add("求函数的定点")
        return self

    def __get_special_points(self, name, expr, sym):
        if isinstance(expr, Pow):
            if (not expr.args[0].has(sym)) and expr.args[1].has(sym):  # 指数型函数
                self.label.add('求指数型函数的定点')
                return JieFangChen(verbose=True).solver(BaseEq([expr.args[1], '0'])).output[0].value[sym]
            elif expr.args[0].has(sym) and (not expr.args[1].has(sym)):  # 幂型函数
                self.label.add('求幂型函数的定点')
                return JieFangChen(verbose=True).solver(BaseEq([expr.args[0], '1'])).output[0].value[sym]
            else:
                return None
        elif isinstance(expr, log):
            if expr.args[0].has(sym):
                self.label.add('求对数型函数的定点')
                return JieFangChen(verbose=True).solver(BaseEq([expr.args[0], '1'])).output[0].value[sym]
            else:
                return None
        elif isinstance(expr, Add) or isinstance(expr, Mul):
            defaultsym = [i for i in expr.free_symbols if i != sym]
            try:
                gongfenmu = list(FenShi001().solver(BaseEq([name, expr])).output[0].value)[0]
            except AssertionError:
                gongfenmu = 1
            eqlist = []
            for s in defaultsym:
                if gongfenmu != 1:
                    eqlist.append([str((Symbol(name) * gongfenmu - expr * gongfenmu).coeff(s)), '0'])
                else:
                    eqlist.append([str(expr.coeff(s)), '0'])
            judge = False
            for eq in eqlist:
                if eq[0] != '0':
                    judge = True
            if judge:
                if len(eqlist) == 1:
                    self.label.add('求非指对幂型函数的定点')
                    return JieFangChen(verbose=True).solver(BaseEq(eqlist[0])).output[0].value[sym]
                else:
                    solution = JieFangChenZu().solver(BaseEqs([eqlist])).output[0].value
                    pointlist = []
                    for k, v in solution.items():
                        pointlist.append([j for j in i for i in v.args])
                    self.output.append(BasePoints({'name': '', 'value': pointlist}))
                    return None
            else:
                for i in expr.args:
                    result = self.__get_special_points(name, i, sym)
                    if result is not None:
                        return result

        return None


if __name__ == '__main__':
    pass
